package com.mrogrape.notepad.ui;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JTextField;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.SwingConstants;
import javax.swing.text.BadLocationException;

import com.mrogrape.notepad.ui.editor.TextEditor;
import com.mrogrape.util.StringUtils;

/**
 * “跳转到行”对话框。
 * 
 * @author Ice Spring
 * @version 1.0
 */
public class GotoLineDialog extends JDialog {
	/**serialVersionUID*/
	private static final long serialVersionUID = 1L;
	
	public GotoLineDialog(Frame frame) {
		super(frame,true);
		initialize();
	}
	
	/**
	 * 显示对话框并执行跳转操作。
	 * 
	 * @param editor 当前操作的编辑器。
	 */
	public void showDialog(TextEditor editor){
		
		if(editor == null){
			return;
		}
		
		this.editor = editor;
		this.lineCount = editor.getLineCount();
		
		if(this.lineCount <= 1){
			return;
		}
		
		this.initTipsLabel();
		this.clearErrorMessage();
		this.lineNumberText.setText("");
		this.lineNumberText.requestFocus();
		this.setVisible(true);
	}
	
	private void initTipsLabel(){
		
		this.tipsLal.setText("Enter line number(1~" + this.lineCount + "):");
	}
	
	/**
	 * 显示一个错误提示消息。
	 * 
	 * @param msg
	 */
	private void displayErrorMessage(String msg){
		
		this.messageView.setText(msg);
	}
	
	/**
	 * 清空错误消息
	 */
	private void clearErrorMessage(){
		
		this.messageView.setText("");
	}
	
	/**
	 * 检查用户的输入是否合法。
	 * 
	 * @return 如果合法则返回true，反之则返回false并显示错误消息。
	 */
	private boolean validateInput(){
		
		String input = this.lineNumberText.getText();
		
		// Empty
		if(StringUtils.isEmpty(input)){
			this.displayErrorMessage("Input a number between 1 and " + this.lineCount + " please.");
			return false;
		}
		
		// Not a Number
		if(!input.matches("\\d*")){
			this.displayErrorMessage("Please input a number.");
			return false;
		}

		// Not a Integer
		if(input.contains(".")){
			this.displayErrorMessage("Please input a integer number.");
			return false;
		}
		
		// Out of bounds
		int line = Integer.parseInt(input);
		if(line < 1 || line > this.lineCount){
			this.displayErrorMessage("Line Number must between 1 and " + this.lineCount + ".");
			return false;
		}
		
		return true;
	}
	
	private void initialize() {
		GroupLayout groupLayout = new GroupLayout(getContentPane());
		groupLayout.setHorizontalGroup(
			groupLayout.createParallelGroup(Alignment.LEADING)
				.addGroup(groupLayout.createSequentialGroup()
					.addContainerGap()
					.addGroup(groupLayout.createParallelGroup(Alignment.LEADING)
						.addComponent(getLineNumberText(), Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 410, Short.MAX_VALUE)
						.addGroup(Alignment.TRAILING, groupLayout.createSequentialGroup()
							.addComponent(getMessageView())
							.addPreferredGap(ComponentPlacement.RELATED, 219, Short.MAX_VALUE)
							.addComponent(getApproveBtn())
							.addPreferredGap(ComponentPlacement.RELATED)
							.addComponent(getCancelBtn()))
						.addComponent(getTipsLal()))
					.addContainerGap())
		);
		groupLayout.setVerticalGroup(
			groupLayout.createParallelGroup(Alignment.LEADING)
				.addGroup(groupLayout.createSequentialGroup()
					.addContainerGap()
					.addComponent(getTipsLal())
					.addPreferredGap(ComponentPlacement.RELATED)
					.addComponent(getLineNumberText(), GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
					.addPreferredGap(ComponentPlacement.RELATED, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
					.addGroup(groupLayout.createParallelGroup(Alignment.BASELINE)
						.addComponent(getCancelBtn())
						.addComponent(getApproveBtn())
						.addComponent(getMessageView()))
					.addContainerGap())
		);
		groupLayout.linkSize(SwingConstants.HORIZONTAL, new Component[] {getApproveBtn(), getCancelBtn()});
		getContentPane().setLayout(groupLayout);
		
		super.setTitle("Go to Line");
		super.setMinimumSize(new Dimension(450,120));
		super.setLocationRelativeTo(this.getOwner());
	}
	
	private JLabel getTipsLal() {
		if (this.tipsLal == null) {
			this.tipsLal = new JLabel("Enter line number");
		}
		return this.tipsLal;
	}
	private JTextField getLineNumberText() {
		if (this.lineNumberText == null) {
			this.lineNumberText = new JTextField();
			this.lineNumberText.setColumns(10);
		}
		this.lineNumberText.addActionListener(this.gotoLineAction);
		return this.lineNumberText;
	}
	
	private JButton getCancelBtn() {
		if (this.cancelBtn == null) {
			this.cancelBtn = new JButton("Cancel");
		}
		this.cancelBtn.addActionListener(new ActionListener(){

			@Override
			public void actionPerformed(ActionEvent e) {

				GotoLineDialog.this.setVisible(false);
			}
		});
		return this.cancelBtn;
	}
	
	private JButton getApproveBtn() {
		if (this.approveBtn == null) {
			this.approveBtn = new JButton("OK");
		}
		this.approveBtn.addActionListener(this.gotoLineAction);
		return this.approveBtn;
	}
	
	private JLabel getMessageView() {
		if (this.messageView == null) {
			this.messageView = new JLabel("");
		}
		this.messageView.setForeground(Color.RED);
		return this.messageView;
	}
	
	private int lineCount = 0;
	private TextEditor editor = null;
	
	private JLabel tipsLal;
	private JTextField lineNumberText;
	private JButton cancelBtn;
	private JButton approveBtn;
	private JLabel messageView;
	
	private GotoLineAction gotoLineAction = new GotoLineAction();
	
	/**
	 * 跳转到行动作处理器。
	 * 
	 * @author 110046
	 *
	 */
	private class GotoLineAction implements ActionListener{

		@Override
		public void actionPerformed(ActionEvent e) {
			
			if(validateInput()){
				
				String input = GotoLineDialog.this.lineNumberText.getText();
				int line = Integer.parseInt(input) - 1;
				try {
					GotoLineDialog.this.editor.setCaretPositionByLine(line);
					GotoLineDialog.this.setVisible(false);
				} catch (BadLocationException e1) {
					displayErrorMessage(e1.getMessage());
					e1.printStackTrace();
				}
			}
		
		}
	}
}
